package com.htfyun.factorytest.engineer_test;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import androidx.annotation.Nullable;

import com.blankj.utilcode.util.VolumeUtils;
import com.htfyun.factorytest.R;
import com.htfyun.factorytest.common.FTUtils;
import com.htfyun.factorytest.myrecorder.IRecordListener;
import com.htfyun.factorytest.myrecorder.RecorderThread;
import com.htfyun.factorytest.playerutils.MediaPlayerTool;
import com.htfyun.factorytest.utils.DebugLog;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class FragmentES7210_MonoTest extends BaseFragment implements View.OnClickListener {
    private static final String RECORDER_FILE_PATH = FTUtils.getFTStorageDirectory() + File.separator + "mic_es7210.pcm";
    private static final String RECORDER_WAV_FILE_PATH = FTUtils.getFTStorageDirectory() + File.separator + "mic_es7210.pcm.wav";
    private static final String RECORDER_MONO_FILE_PATH = FTUtils.getFTStorageDirectory() + File.separator + "mic_es7210_mono.pcm";

    private final int SampleRateInHz = 16000;

    private final static int STATE_WANT_RECORD = 0;
    private final static int STATE_WANT_PLAY = STATE_WANT_RECORD + 1;
    private final static int STATE_WANT_CHECK = STATE_WANT_PLAY + 1;

    private int recordState = STATE_WANT_RECORD;

    private TextView txtInfo;
    private TextView txtStatus;
    private TextView txtPassTips;
    private Button btnPass;
    private Button btnFail;
    private Button btnRepeat;
    private Button btnRecordAndPlay;

    private MediaPlayerTool mediaPlayerTool;
    private MediaPlayer mediaPlayer;

    //先左后右
    private MicInfoAttr micInfoAttr = MicInfoAttr.left;

    private OnBtnResultForES7210 onBtnResultForES7210;

    public void setOnBtnResultForES7210(OnBtnResultForES7210 onBtnResultForES7210) {
        this.onBtnResultForES7210 = onBtnResultForES7210;
    }

    @Override
    protected int getLayoutRes() {
        return R.layout.fragment_engineer_es7210_mono_test;
    }

    @Override
    protected void onInitView(@Nullable Bundle savedInstanceState) {

        txtInfo = findViewById(R.id.txtInfo);
        txtStatus = findViewById(R.id.txtStatus);
        txtPassTips = findViewById(R.id.txtPassTips);
        btnPass = findViewById(R.id.btnPass);
        btnFail = findViewById(R.id.btnFail);
        btnRepeat = findViewById(R.id.btnRepeat);
        btnRecordAndPlay = findViewById(R.id.btnRecordAndPlay);

//        txtStatus.setVisibility(View.INVISIBLE);

        btnPass.setOnClickListener(this);
        btnFail.setOnClickListener(this);
        btnRepeat.setOnClickListener(this);
        btnRecordAndPlay.setOnClickListener(this);

        DebugLog.e("getHandler = " + getHandler());

        mediaPlayerTool = MediaPlayerTool.getInstance(getContext(), getHandler());

    }

    private volatile boolean isHeadsetRegistered = false;

    @Override
    protected void onVisible() {
        super.onVisible();

        doOnVisible();
    }

    private void doOnVisible() {
        updateMicInfo();
        setBtnPassFailGone(true);
        txtStatus.setText("");
        btnRepeat.setEnabled(false);

//        updateBtnUI(recordState);

//        if (!isHeadsetRegistered) {
//            isHeadsetRegistered = true;
//            //发送广播检测耳机插入状态
//            IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
//            mContext.registerReceiver(headsetPlugReceiver, filter);
//        }
    }

    @Override
    protected void onInvisible() {
        super.onInvisible();
        stopRecord();
        stopPlay();

//        if (isHeadsetRegistered) {
//            isHeadsetRegistered = false;
//            mContext.unregisterReceiver(headsetPlugReceiver);
//        }
    }

//    private void updateBtnUI(int state) {

//        if (state == STATE_WANT_RECORD) {
//
//            setBtnPassFailGone(true);
//            btnRecordAndPlay.setText(R.string.mic_record);
//
//            txtStatus.setVisibility(View.INVISIBLE);
//
//        } else if (state == STATE_WANT_PLAY) {
//
//            setBtnPassFailGone(true);
//            btnRecordAndPlay.setText(R.string.mic_play);
//
//            txtStatus.setVisibility(View.VISIBLE);
//            txtStatus.setText(R.string.mic_status_recording);
//
//
//        } else if (state == STATE_WANT_CHECK) {
//
//            setBtnPassFailGone(false);
//            txtStatus.setVisibility(View.VISIBLE);
//            txtStatus.setText(R.string.mic_status_playing);
//
//        }
//
//        txtInfo.setText(micInfoAttr.getInfoResId());
//        btnPass.setText(micInfoAttr.getPassResId());
//        btnFail.setText(micInfoAttr.getFailResId());
//    }

    private void setBtnPassFailGone(boolean gone) {
//        btnPass.setVisibility(gone ? View.INVISIBLE : View.VISIBLE);
//        btnFail.setVisibility(gone ? View.INVISIBLE : View.VISIBLE);
        btnPass.setEnabled(!gone);
        btnFail.setEnabled(!gone);

//        btnRecordAndPlay.setVisibility(gone ? View.VISIBLE : View.INVISIBLE);

    }

    @Override
    public void onClick(View v) {

        if (v == btnRecordAndPlay) {

//            recordState++;
//            updateBtnUI(recordState);

//            if (recordState == STATE_WANT_PLAY) {
//                startRecord();
//            } else if (recordState == STATE_WANT_CHECK) {
//                stopRecord();
//                startPlay();
//            }

            clickBtnRecord();


        } else if (v == btnPass) {

            onClickBtnPassOrFail();

            if (micInfoAttr == MicInfoAttr.left) {

                micInfoAttr = MicInfoAttr.right;
                setBtnPassFailGone(true);
                startPlay();

            } else if (micInfoAttr == MicInfoAttr.right) {

                if (onBtnResultForES7210 != null) {
                    onBtnResultForES7210.onBtnResultForES7210(true);
                    findViewById(R.id.btnFail).setSelected(false);
                    findViewById(R.id.btnPass).setSelected(false);
                    v.setSelected(true);
                    txtPassTips.setText(R.string.record_pass);
                } else {
                    micInfoAttr = MicInfoAttr.left;
                }

            }

//            recordState = STATE_WANT_RECORD;
//            updateBtnUI(recordState);

            updateMicInfo();

        } else if (v == btnFail) {

            onClickBtnPassOrFail();

            if (onBtnResultForES7210 != null) {
                onBtnResultForES7210.onBtnResultForES7210(false);
                findViewById(R.id.btnFail).setSelected(false);
                findViewById(R.id.btnPass).setSelected(false);
                v.setSelected(true);
                txtPassTips.setText(R.string.record_fail);
            }
        } else if (v == btnRepeat) {
            startPlay();
        }

    }

    private void clickBtnRecord() {
        updateMicInfo();

        stopPlay();
        DebugLog.e("startRecord");
        startRecord();

        setBtnPassFailGone(true);

        txtStatus.setText(R.string.mic_status_recording);
        setBtnRecordEnabled(false);

        getHandler().sendEmptyMessageDelayed(MSG_RECORD_OVER, DELAY_RECORD_OVER);
    }

    private void onClickBtnPassOrFail() {
//        btnRepeat.setEnabled(false);
        stopRecord();
        stopPlay();
        getHandler().postDelayed(() -> txtStatus.setText(""), 200);
    }

    private void updateMicInfo() {
        txtInfo.setText(micInfoAttr.getInfoResId());
        btnPass.setText(micInfoAttr.getPassResId());
        btnFail.setText(micInfoAttr.getFailResId());
    }

    private void setBtnRecordEnabled(boolean enabled) {
/*        Button btnRecord = findViewById(R.id.btnRecordAndPlay);
        if (btnRecord == null) {
            return;
        }*/
        btnRecordAndPlay.setEnabled(enabled);
        btnRepeat.setEnabled(enabled);
    }

    //////////////////////
    //    play
    /////////////////////
    private void startPlay() {
        setBtnPassFailGone(true);
        setBtnRecordEnabled(false);
        stopPlay();
        VolumeUtils.setVolume(AudioManager.STREAM_MUSIC, VolumeUtils.getMaxVolume(AudioManager.STREAM_MUSIC), 0);

//        if (mediaPlayerTool == null) {
//            mediaPlayerTool = MediaPlayerTool.getInstance(getContext(), getHandler());
//        }
        txtStatus.setText(R.string.mic_status_playing);
//        mediaPlayerTool.playPcm(RECORDER_MONO_FILE_PATH);
        mediaPlayer = new MediaPlayer();
        try {
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mediaPlayer.setDataSource(requireActivity().getApplicationContext(), Uri.parse(RECORDER_WAV_FILE_PATH));
            mediaPlayer.setOnPreparedListener(mp -> {
                mediaPlayer.setVolume(micInfoAttr == MicInfoAttr.left ? 1.0F : 0F,
                        micInfoAttr == MicInfoAttr.left ? 0F : 1.0F);
                mediaPlayer.start();
            });
            mediaPlayer.setOnCompletionListener(mediaPlayer -> {
                mediaPlayer.release();
                mediaPlayer = null;
                getHandler().sendEmptyMessage(MediaPlayerTool.EVENT_PLAY_OVER);
            });
            mediaPlayer.prepareAsync();
        } catch (Exception e) {
            Log.e("ERROR", e.toString());
        }

//        getHandler().sendEmptyMessageDelayed(MediaPlayerTool.EVENT_PLAY_OVER, DELAY_RECORD_OVER);
//        getHandler().postDelayed(() -> txtStatus.setText(R.string.mic_status_playing), 300);

    }

    private void stopPlay() {
        mediaPlayerTool.stop();
//        mediaPlayer.stop();
        txtStatus.setText(R.string.mic_status_playing_stop);

    }

    //////////////////////
    //    Recorder
    /////////////////////
    private RecorderThread recorderThread;


    public void startRecord() {
        startRecordTread();
    }

    private void stopRecord() {
        stopRecordThread();

    }

    private void startRecordTread() {

        if (recorderThread != null) {
            stopRecordThread();
        }

        recorderThread = new RecorderThread("es7210-", null, RECORDER_FILE_PATH);
        recorderThread.getRecorderOperator().setChannelConfig(AudioFormat.CHANNEL_IN_STEREO);
        recorderThread.getRecorderOperator().setRecordingListener(recordListener);
        recorderThread.getRecorderOperator().setSampleRateInHz(SampleRateInHz);
        recorderThread.getRecorderOperator().setAudioFormat(AudioFormat.ENCODING_PCM_16BIT);
        recorderThread.start();

    }

    private void stopRecordThread() {

        if (recorderThread != null) {
            recorderThread.joinThread();
            recorderThread = null;
        }
    }

    private volatile boolean keepAlive = true;
    private BlockingQueue<ByteBuffer> audioDataQueue = new LinkedBlockingQueue<>(128);

    private Runnable saveMonoRunnable = () -> {
//        BufferedOutputStream bos = null;
        FileOutputStream bos = null;

        try {

            File file = new File(RECORDER_MONO_FILE_PATH);
            if (file.exists()) {
                file.delete();
            }

//            bos = new BufferedOutputStream(new FileOutputStream(file));
            bos = new FileOutputStream(file);

            keepAlive = true;
            while (keepAlive) {

                ByteBuffer byteBuffer = audioDataQueue.take();
//                ByteBuffer byteBuffer2 = byteBuffer;
                if (byteBuffer != null && byteBuffer.array().length != 1) {
//                    byte[] buffer = new byte[byteBuffer.array().length];
//                    byte[] buffer = new byte[byteBuffer.array().length / 2];
                    for (int n = 0, i = 0; i < byteBuffer.array().length; ) {
                        if (micInfoAttr == MicInfoAttr.left) {
                            n += 4;
                            i += 2;
                        }
/*                        buffer[i] = byteBuffer.array()[i];
                        i++;
                        buffer[i] = byteBuffer.array()[i];
                        i++;*/

//                        buffer[i] = 0;
                        byteBuffer.array()[i] = 0;
                        i++;
//                        buffer[i] = 0;
                        byteBuffer.array()[i] = 0;
                        i++;
/*                        n++;
                        n++;
                        buffer[i++] = byteBuffer.array()[n++];
                        buffer[i++] = byteBuffer.array()[n++];*/
                        if (micInfoAttr == MicInfoAttr.right) {
                            n += 4;
                            i += 2;
                        }
                    }

                    bos.write(byteBuffer.array(), 0, byteBuffer.array().length);
//                    bos2.write(buffer, 0, buffer.length);
                    bos.flush();
//                    bos2.flush();
//                    buffer = null;
                    byteBuffer = null;
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            audioDataQueue.clear();

            DebugLog.e("write file finish..........................");

            if (bos != null) {
                try {
                    bos.flush();
                    bos.close();
                } catch (IOException ignored) {
                }
            }
        }
    };

    private IRecordListener recordListener = new IRecordListener() {

        @Override
        public void onRecordingData(byte[] audioData, int validSize) {
            DebugLog.e("onRecordingData");
            /*int size = Math.min(audioData.length, validSize);
            try {
                audioDataQueue.clear();
                audioDataQueue.add(ByteBuffer.wrap(audioData, 0, size));
            } catch (Exception e) {
                DebugLog.e("error " + e.getMessage());
            }*/

        }

        @Override
        public void onRecordingStart() {
            DebugLog.e("onRecordingStart");
//            AppExecutors.runOnIoThread(saveMonoRunnable);
//            AppExecutors.postToMainThread(() -> Toast.makeText(mContext, R.string.record_start, Toast.LENGTH_SHORT).show());
        }

        @Override
        public void onRecordingStop() {

//            keepAlive = false;
            //保证saveMonoRunnable能退出
            /*byte[] buffer = new byte[1];
            try {
                audioDataQueue.add(ByteBuffer.wrap(buffer, 0, buffer.length));
            } catch (IllegalStateException e) {
                DebugLog.e(e.getMessage());
            }*/
            DebugLog.e("onRecordingStop");
//            AppExecutors.postToMainThread(() -> Toast.makeText(mContext, R.string.record_stop, Toast.LENGTH_SHORT).show());
        }
    };
    //////////////////////////

//    private BroadcastReceiver headsetPlugReceiver = new BroadcastReceiver() {
//
//        @Override
//        public void onReceive(Context context, Intent intent) {
//            final String action = intent.getAction();
//
//            if (action != null && action.equals(Intent.ACTION_HEADSET_PLUG)) {
//                if (intent.hasExtra("state")) {
//                    boolean unplug = (intent.getIntExtra("state", 0) == 0);
//                    DebugLog.e("unplug = " + unplug);
//
//                    setBtnRecordEnabled(unplug);
//
//                }
//            }
//        }
//    };

    private final int MSG_RECORD_OVER = 10;
    private final int DELAY_RECORD_OVER = 5000;
//    private final int DELAY_RECORD_OVER = 3000;

    @Override
    protected void handleMessage(Message msg) {
        super.handleMessage(msg);
        DebugLog.e("msg.what = " + msg.what);
        if (msg.what == MediaPlayerTool.EVENT_PLAY_OVER) {
            DebugLog.e("play over");
            stopPlay();
//            txtStatus.setText(R.string.mic_status_playing_stop);
            getHandler().postDelayed(() -> {
                setBtnPassFailGone(false);
                setBtnRecordEnabled(true);
            }, 2000);

        } else if (msg.what == MSG_RECORD_OVER) {
            txtStatus.setText(R.string.mic_status_recording_stop);
            stopRecord();
            getHandler().postDelayed(this::startPlay, 1000);
//            setBtnPassFailGone(false);
//            getHandler().postDelayed(() -> setBtnRecordEnabled(true), 1000);
//            btnRepeat.setEnabled(true);

        }
    }

    private enum MicInfoAttr {
        left(R.string.mic_info_left, R.string.mic_result_left_pass, R.string.mic_result_left_fail),
        right(R.string.mic_info_right, R.string.mic_result_right_pass, R.string.mic_result_right_fail),
        ;

        private final int infoResId;
        private final int passResId;
        private final int failResId;

        MicInfoAttr(int infoResId, int passResId, int failResId) {
            this.infoResId = infoResId;
            this.passResId = passResId;
            this.failResId = failResId;
        }

        public int getInfoResId() {
            return infoResId;
        }

        public int getPassResId() {
            return passResId;
        }

        public int getFailResId() {
            return failResId;
        }
    }

}
